<?php

   if ( !defined( "RUTA_FISICA_SISTEMA" ) )
    {
      require_once '../../../config/Constantes.php';
    }
    
   $ruta_sistema = RUTA_FISICA_SISTEMA . "/sistema/"; 

include_once $ruta_sistema . "general/clases/comun/base_datos/OperacionBDInterface.php";
include_once $ruta_sistema . "general/clases/comun/logger/Log.php";
include_once $ruta_sistema . "general/clases/comun/base_datos/DataBase.php";

/** 
 * @author juanjo
 * 
 * 
 */
class OperacionBD implements OperacionBDInterface
   {
      private static $_log;

      //TODO - Insert your code here
      function __construct( )
         {
            //TODO - Insert your code here
           // self::$_log = new Logger( __CLASS__ ); 
         }
	   
        /**
         * 
         * Metodo: guardar
         * Descripcion: Genera la consulta correspondiente al insert en MySql con los valores que se le envien en los parametros
         * Fecha de Creacion: 19/04/2012 15:21:54
         * Autor: Juan José Muñiz Juárez
         * params: @param unknown_type $tabla : Nombre de la tabla en donde se va a insertar o actualizar el registro
          * params: @param unknown_type $campos : Nombre del o los campos que se veran afectados por la operacion
          * params: @param unknown_type $valores : Valores que tendra cada campo, estos deben coincidir, si se envian como array deben
          *                                        tener el mismo numero de elementos y si se envia como cadena, se utilizara el valor
          *                                        que tenga el parametro $separador_campos para verificar que el numero de elementos
          *                                        sea igual al de los campos
          * params: @param unknown_type $filtro : Filtro adicional que se le puede aplicar a la consulta cuando se va a actualizar la informacion
          * params: @param unknown_type $separador_campos : Por default tiene el valor "," que se utiliza para separar los campos en el insert
          * params: @param unknown_type $array_valores: bandera que se utiliza para verificar si los valores se envian por array o por cadena
          * params: @param unknown_type $campos_valores : Bandera que se utiliza para verificar si se ha enviado el parametro campo como un array
          *                                               asociativo con el nombre del campo asignandole el valor correspondiente
          *                                               ejemplo:
          *                                                        array( "nombre" => "Juan Jose", "apaterno" => "Muñiz", "amaterno" => "Juarez" )        
          * params: @param unknown_type $class : Clase desde donde se invoca la funcion, si no se especifica se envia por default la clase OperacionBD
          * params: @param unknown_type $method : Metodo desde donde se invoca la funcion, si no se especifica senvia el metodo donde se ejecuta la operacion
          * params: @param unknown_type $line : Linea desde donde se invoca la funcion, si no se especifica se envia la linea desde donde se ejecuta la operacion
         * params: @return Ambigous <NULL, resource>
         * return: Ambigous <NULL, resource>
         */
      public static function guardar( $tabla, $campos, $valores, $filtro, $separador_campos = ",", $array_valores = false, $campos_valores = false, $class = null, $method = null, $line = null, $generar_log = true )
        {
           return self::agregarInformacion($tabla, $campos, $valores, false, $filtro, $separador_campos, $array_valores, $campos_valores, $class, $method, $line , $generar_log );
        }  

        /**
         * 
         * Metodo: actualizar
         * Descripcion: 
         * Fecha de Creacion: 19/04/2012 15:21:58
         * Autor: Juan José Muñiz Juárez
         * params: @param unknown_type $tabla : Nombre de la tabla en donde se va a insertar o actualizar el registro
          * params: @param unknown_type $campos : Nombre del o los campos que se veran afectados por la operacion
          * params: @param unknown_type $valores : Valores que tendra cada campo, estos deben coincidir, si se envian como array deben
          *                                        tener el mismo numero de elementos y si se envia como cadena, se utilizara el valor
          *                                        que tenga el parametro $separador_campos para verificar que el numero de elementos
          *                                        sea igual al de los campos
          * params: @param unknown_type $filtro : Filtro adicional que se le puede aplicar a la consulta cuando se va a actualizar la informacion
          * params: @param unknown_type $separador_campos : Por default tiene el valor "," que se utiliza para separar los campos en el insert o update
          * params: @param unknown_type $array_valores: bandera que se utiliza para verificar si los valores se envian por array o por cadena
          * params: @param unknown_type $campos_valores : Bandera que se utiliza para verificar si se ha enviado el parametro campo como un array
          *                                               asociativo con el nombre del campo asignandole el valor correspondiente
          *                                               ejemplo:
          *                                                        array( "nombre" => "Juan Jose", "apaterno" => "Muñiz", "amaterno" => "Juarez" )        
          * params: @param unknown_type $class : Clase desde donde se invoca la funcion, si no se especifica se envia por default la clase OperacionBD
          * params: @param unknown_type $method : Metodo desde donde se invoca la funcion, si no se especifica senvia el metodo donde se ejecuta la operacion
          * params: @param unknown_type $line : Linea desde donde se invoca la funcion, si no se especifica se envia la linea desde donde se ejecuta la operacion
         * params: @return Ambigous <NULL, resource>
         * return: Ambigous <NULL, resource>
         */
      public static function actualizar( $tabla, $campos, $valores, $filtro, $separador_campos = ",", $array_valores = false, $campos_valores = false, $class = null, $method = null, $line = null, $generar_log = true )  
        {
           return self::agregarInformacion($tabla, $campos, $valores, true, $filtro, $separador_campos, $array_valores, $campos_valores, $class, $method, $line, $generar_log );
        }
         
         /**
          * 
          * Metodo: agregarInformacion
          * Descripcion: 
          * Fecha de Creacion: 19/04/2012 15:22:57
          * Autor: Juan José Muñiz Juárez
          * params: @param unknown_type $tabla : Nombre de la tabla en donde se va a insertar o actualizar el registro
          * params: @param unknown_type $campos : Nombre del o los campos que se veran afectados por la operacion
          * params: @param unknown_type $valores : Valores que tendra cada campo, estos deben coincidir, si se envian como array deben
          *                                        tener el mismo numero de elementos y si se envia como cadena, se utilizara el valor
          *                                        que tenga el parametro $separador_campos para verificar que el numero de elementos
          *                                        sea igual al de los campos
          * params: @param unknown_type $actualizar : Bandera que se utiliza para verificar si se va a actualizar la informacion
          * params: @param unknown_type $filtro : Filtro adicional que se le puede aplicar a la consulta cuando se va a actualizar la informacion
          * params: @param unknown_type $separador_campos : Por default tiene el valor "," que se utiliza para separar los campos en el insert o update
          * params: @param unknown_type $array_valores: bandera que se utiliza para verificar si los valores se envian por array o por cadena
          * params: @param unknown_type $campos_valores : Bandera que se utiliza para verificar si se ha enviado el parametro campo como un array
          *                                               asociativo con el nombre del campo asignandole el valor correspondiente
          *                                               ejemplo:
          *                                                        array( "nombre" => "Juan Jose", "apaterno" => "Muñiz", "amaterno" => "Juarez" )        
          * params: @param unknown_type $class : Clase desde donde se invoca la funcion, si no se especifica se envia por default la clase OperacionBD
          * params: @param unknown_type $method : Metodo desde donde se invoca la funcion, si no se especifica senvia el metodo donde se ejecuta la operacion
          * params: @param unknown_type $line : Linea desde donde se invoca la funcion, si no se especifica se envia la linea desde donde se ejecuta la operacion
          * params: @throws Exception
          * params: @return resource|NULL
          * return: resource|NULL
          */
      private static function agregarInformacion( $tabla, $campos, $valores, $actualizar, $filtro, $separador_campos, $array_valores, $campos_valores, $class, $method, $line, $generar_log = true )
         {
            if ( !$tabla || !$campos || ( $campos_valores == false && !$valores ) )
              {
                 throw new Exception( "Es necesario que se especifiquen los valores para la tabla, los campos y valores" );
              }
            
            if ( $generar_log )
              {
                  self::getLogger( $class );
      
                  self::$_log -> info( "Invocando el metodo guardar/actualizar un registro con la siguiente informacion " . PHP_EOL . 
                                        " Tabla : " . $tabla . PHP_EOL . 
                                        " Campos : " . $campos . PHP_EOL .
                                        " Valores : " . $valores . PHP_EOL . 
                                        " Actualizar : " . $actualizar . PHP_EOL . 
                                        " Filtro : " . $filtro . PHP_EOL .
                                        " Separador de Campos : " . $separador_campos . PHP_EOL .
                                        " Valores enviados por Arreglo : " . $array_valores . PHP_EOL .
                                        " Arreglo Bidimensional con campos y valores : " . $campos_valores . PHP_EOL .
                                        " Separador de Campos : " . $separador_campos . PHP_EOL .
                                        " Clase que invoca : " . $class . PHP_EOL .
                                        " Metodo que invoca : " . $method . PHP_EOL .
                                        " Linea desde donde se invoca : " . $line . PHP_EOL .
                                         ( $method == null ? __METHOD__ : $method ),
                                         ( $line == null ? __LINE__ : $line ) );
              }
                  
             // echo "[" . $actualizar . "]";
            if ( $actualizar )
              {
                 $tmp_campos = array();
                 $tmp_valores = array();
                   
                  if ( $array_valores )
                    { 
                        if ( is_array( $campos ) && is_array( $valores ) )
                          {
                             if ( count( $campos ) != count( $valores ) )
                               {
                                  throw new Exception( "La cantidad de valores debe ser igual a la cantidad de valores que se envian" );
                               }
                               
                             $tmp_campos = $campos;
                             $tmp_valores = $valores;  
                          } 
                        else
                          {
                             if ( $campos_valores )
                               {
                                  if ( is_array( $campos ) )
                                    {
                                       $tmp_valores = array();
                                       $tmp_campos = array();
                                       
                                       foreach ( $campos as $campo => $valor )
                                         {
                                            $tmp_valores[] = $valor;
                                            $tmp_campos[] = $campo;
                                         }
                                    }
                               }
                             else  
                               {
                                  throw new Exception( "Se deben especificar los valores y campos como arreglo si utiliza la bandera array_valores como verdadera" );
                               }
                          }                      
                    }
                  else
                    {
                       if ( $separador_campos )
                        {
                          if ( strpos( $campos , $separador_campos ) !== false && strpos( $valores , $separador_campos ) !== false )
                            {
                               $tmp_campos = explode( $separador_campos, $campos );
                               $tmp_valores = explode( $separador_campos, $valores );
                               
                               if ( is_array( $tmp_campos ) && is_array( $tmp_valores ) )
                                 {
                                    if ( count( $campos ) != count( $valores ) )
                                     {
                                        throw new Exception( "La cantidad de valores debe ser igual a la cantidad de valores que se envian" );
                                     }
                                 }
                            }
                        }
                      else
                       {
                          $tmp_valores[] = $valores;
                          $tmp_campos[] = $campos;
                       }   
                    } 

                  $query = "Update $tabla "; 

                  $contador = 0;
                  
                  foreach( $tmp_campos as $nombre_campo )
                    {
                       $query .= ( $contador == 0 ? " SET " : ", " ) . " $nombre_campo = '" .  self::eliminarCaracteresEspeciales( $tmp_valores[ $contador ] ). "' ";
                       $contador++;
                    }
                  
                  $query .= " " . $filtro;
                  
                  return DataBase::update( $query, $class, $method, $line );
              }
            else
              {
                 if ( $array_valores )
                   {
                      if ( $campos_valores )
                        {
                          if ( is_array( $campos ) )
                            {
                              $tmp_valores = array();
                              $tmp_campos = array();
                              
                              foreach ( $campos as $campo => $valor )
                                {
                                   $tmp_valores[] = $valor;
                                   $tmp_campos[] = $campo;
                                }
                           }
                         else
                           {
                              throw new Exception( "Se debe especificar el array campos con la informacion de los nombres y sus respectivos valores" );
                           }  
                       }
                   }
                 else
                   {  
                      $tmp_campos = explode( $separador_campos, $campos );
                      $tmp_valores = explode( $separador_campos, $valores );
                   }
                   
                  //var_dump( $tmp_campos, $tmp_valores ); 
                   
                  if ( is_array( $tmp_campos ) && is_array( $tmp_valores ) )
                     {
                        if ( count( $tmp_campos ) != count( $tmp_valores ) )
                          {
                            throw new Exception( "La cantidad de valores debe ser igual a la cantidad de valores que se envian" );
                          }
                        else
                          {
                             $contador = 0;
                             $campos = "";
                             $valores = "";
                             
                             foreach( $tmp_campos as $tmp_campo )
                               {
                                   $campos .= ( $contador == 0 ? "" : "," ) . $tmp_campo ;
                                   
                                   if ( $tmp_valores[ $contador ] )
                                     {
                                        $valor = $tmp_valores[ $contador ];
                                        
                                        if ( !is_array( $valor ) )
                                          {
                                            if ( strpos( strtolower( $valor ) , "now()" ) !== false )
                                              {
                                                $valores .= ( $contador == 0 ? "" : "," ) . self::eliminarCaracteresEspeciales(  $valor );
                                                $contador++;
                                                continue;
                                              }
                                          }                                          
                                     }
                                     
                                   $valores .= ( $contador == 0 ? "" : "," ) . "'" . $tmp_valores[ $contador ]. "'";
                                   
                                   $contador++;
                               }
                          }  
                     }
                     
                     
                   $query = "Insert Into $tabla ( $campos ) Values( $valores )";

                   return DataBase::insert( $query, $class, $method, $line  );
              }  
              
              
            return null;
         }
         
         /**
          * 
          * Nombre         	: 	eliminarCaracteresEspeciales
          * Descripcion   	:	Elimina los caracters especiales de la cadena de SQL
          * Version    	    :  	1.0
          * Autor:			:	Juan Jose Muñiz Juarez
          * Fecha y Hora	:	21/04/2012, 02:39:54
          * @param unknown_type $cadena
          * @return string
          */
       private function eliminarCaracteresEspeciales( $cadena )
         {
            return mysql_real_escape_string( $cadena );
         }  
   
         /**
          * 
          * Nombre         	: 	eliminar
          * Descripcion   	:	
          * Version 		:  	1.0
          * Autor:			:	Juan Jose Muñiz Juarez
          * Fecha y Hora	:	18/04/2012 15:56:40
          * @param  $tabla
          * @param  $campo
          * @param  $valor
          * @param  $filtro_adicional
          * @param  $class
          * @param  $method
          * @param  $line
          * @param  $generar_log
          * @throws Exception
          * @return Ambigous <NULL, resource>
          */
      public static function eliminar( $tabla, $campo = "", $valor = "", $filtro_adicional = "", $class = null, $method = null, $line = null, $generar_log = true )
         {
            if ( $generar_log )
              {
                self::getLogger( $class );
               
                self::$_log ->info( "Eliminando el registro coincidente con el campo [ $campo ] 
                                        y el valor[ $valor ] de la tabla [$tabla] con el filtro adicional [ $filtro_adicional ]",
                                      ( $method == null ? __METHOD__ : $method ),
                                      ( $line == null ? __LINE__ : $line ) );
              }
            
            // TODO Auto-generated method stub
            if ( !$tabla )
              {
                 //self::$_log ->warn( "El nombre de la tabla no contiene informacion parametro tabla: [$tabla] ", __METHOD__, __LINE__ );
                 throw new Exception( "Error : El nombre de la tabla no se ha especificado: clase[ " . __CLASS__ . " ] Metodo: [ " . __METHOD__ . " ] linea [ " . __LINE__ . " ]" );
              }
              
            $query = "Delete From $tabla";
            
            if ( $campo && $valor )
              {
                 $query .= " Where $campo = '$valor'";
              }
              
            if ( $filtro_adicional )
              {
                 //$query .= ( strpos( $query , "where" ) !== false ? "" : "" )
                 $query .= "  ". $filtro_adicional;
              }  
              
            return DataBase::delete( $query );
            
         }
   
	  /**
	   * 
	   * Nombre        	: 	buscar
	   * Descripcion   	:	
	   * Version 		:  	1.0
	   * Autor:			:	Juan Jose Muñiz Juarez
	   * Fecha y Hora	:	18/04/2012 16:00:18
	   * @param unknown_type $tabla
	   * @param unknown_type $campos_obtener
	   * @param unknown_type $filtro
	   * @param unknown_type $class
	   * @param unknown_type $method
	   * @param unknown_type $line
	   * @param unknown_type $generar_log
	   * @throws Exception
	   * @return Ambigous <NULL, resource>
	   */
      public static function buscar( $tabla, $campos_obtener = "", $filtro = "", $class = null, $method = null, $line = null, $generar_log = true  )
         {
            if ( $generar_log )
              {
                  self::getLogger( $class );
                  
                  self::$_log ->info( "Buscando en la tabla [$tabla] con el filtro [$filtro]",
                                       ( $method == null ? __METHOD__ : $method ),
                                       ( $line == null ? __LINE__ : $line ) );
              }
              
            // TODO Auto-generated method stub
            if ( !$tabla )
              {
                 //self::$_log ->warn( "El nombre de la tabla no contiene informacion parametro tabla: [$tabla] ", __METHOD__, __LINE__ );
                 throw new Exception( "Error : El nombre de la tabla no se ha especificado: clase[ " . __CLASS__ . " ] Metodo: [ " . __METHOD__ . " ] linea [ " . __LINE__ . " ]" );
              }
              
            $query = "Select " . ( !$campos_obtener ? $campos_obtener : "*" ) . " 
                     From $tabla " . 
                   ( !$filtro ? " Where $filtro " : "" ) ;
            
            self::$_log ->info( "Consulta ejecutada [ $query ]",
                                 ( $method == null ? __METHOD__ : $method ),
                                 ( $line == null ? __LINE__ : $line ) );
            
            return DataBase::query( $query );
         }
         
         /**
          * 
          * Nombre         	: 	existeRegistro
          * Descripcion   	:	
          * Version 		:  	1.0
          * Autor:			:	Juan Jose Muñiz Juarez
          * Fecha y Hora	:	18/04/2012 16:00:54
          * @param unknown_type $tabla
          * @param unknown_type $campo
          * @param unknown_type $valor
          * @param unknown_type $class
          * @param unknown_type $method
          * @param unknown_type $line
          * @param unknown_type $generar_log
          * @throws Exception
          * @return boolean
          */
      public static function existeRegistro( $tabla, $campo, $valor, $class = null, $method = null, $line = null, $generar_log = true )
        {
           if ( $generar_log )
             {
                 self::getLogger( $class );
                 
                 self::$_log -> info( "Verificando si existe el valor [$valor] registrado en el campo[$campo] en la tabla [ $tabla ]",
                                       ( $method == null ? __METHOD__ : $method ),
                                       ( $line == null ? __LINE__ : $line ) );
             }
             
           if ( !$tabla || !$campo || !$valor )
              {
                 if ( $generar_log )
                   {
                    self::$_log -> warn( "Es necesario el nombre de la tabla y el campo en el que se desea verificar el valor proporcionado",
                                          ( $method == null ? __METHOD__ : $method ),
                                          ( $line == null ? __LINE__ : $line ) );
                   }
                   
                 throw new Exception( "Error : El nombre de la tabla, campo o valor no se ha especificado" );
              }
              
           $query = "Select $campo 
                     From $tabla
                     Where $campo = '$valor'
                    limit 1";

           $existe_registro = false;
           
           try
             {
                //self::$_log -> info( "Ejecutando la sigu" )
                $resultados = DataBase::query( $query );
                
                if ( $generar_log )
                  {
                    self::$_log -> info( "Se ha ejecutado la siguiente query: " . PHP_EOL . "[ $query ]", 
                                    ( $method == null ? __METHOD__ : $method ),
                                    ( $line == null ? __LINE__ : $line ) );
                  }
                  
                if ( $resultados )
                 {
                    $existe_registro = mysql_num_rows( $resultados ) > 0;
                 }
             }
           /*catch ( SQLException $sqle )
             {
                self::$_log -> error( "Se ha generado el siguiente error en la consulta" . 
                                        " Error : " . $sqle -> getMessage() . 
                                        " Codigo: " . $sqle -> getCode() .
                                        " Archivo: " . $sqle -> getFile() .
                                        " Linea: " . $sqle -> getLine() . 
                                        " Codigo: " . $sqle -> getTrace() . 
                                        " Query Ejecutada [ $query ]", __METHOD__, __LINE__ );
             }  */
           catch ( Exception $ex )  
             {
                if ( $generar_log )
                  {
                    self::$_log -> error( "Se ha generado el siguiente error en la consulta" .
                                           " Error : " . $ex -> getMessage() .
                                           " Codigo: " . $ex -> getCode() .
                                           " Archivo: " . $ex -> getFile() .
                                           " Linea: " . $ex -> getLine() .
                                           " Codigo: " . $ex -> getTrace() .
                                           " Query Ejecutada [ $query ]",
                                          ( $method == null ? __METHOD__ : $method ),
                                          ( $line == null ? __LINE__ : $line ) );
                  }
             }
           
           return $existe_registro;
        }   
   
	/**
	 * 
	 * Nombre         	: 	listar
	 * Descripcion   	:	Devuelve los resultados obtenidos al ejecutar la consulta
	 * Version 			:  	1.0
	 * Autor:			:	Juan Jose Muñiz Juarez
	 * Fecha y Hora		:	21/04/2012, 02:16:35
	 * @param  $tabla   :   Tabla desde la cual se van a obtener los resultados
	 * @param  string $campos  :   Campos que se van a seleccionar en la consulta, 
	 *                                  por defalt se utiliza * para obtener todos los registros de la tabla 
	 * @param  string $filtro   :   Filtro que se añadira a la sentencia Select, 
	 *                                   esta debe contener la clausula Where para que funcione correctamente la consulta 
	 * @param  $class : Clase que invoca el metodo, si no se especifica se envia la clase del metodo listar
	 * @param  $method : Metodo que invoca esta funcion, si no se especifica se utiliza la funcion del metodo listar
	 * @param  $line   : Linea desde la que se invoca esta funcion, si no se especifica se utiliza la funcion del metodo listar
	 * @param  $generar_log
	 * @return Ambigous <NULL, resource>
	 */
      public static function listar( $tabla, $campos = "*", $filtro = "", $class = null, $method = null, $line = null, $generar_log = true  )
         {
            self::getLogger( $class );
            
            self:: $_log -> info( "Listando la informacion de la tabla [$tabla] con los siguientes filtros[$filtro]", 
                                 ( $method ==  null ? __METHOD__ : $method ),
                                 ( $line ==  null ? __LINE__ : $line ) );    

            $query = " Select $campos 
                       From $tabla 
                       $filtro ";
            
            return DataBase::query( $query, 
                                    ( $class ==  null ? __CLASS__ : $class ),
                                    ( $method ==  null ? __METHOD__ : $method ),
                                    ( $line ==  null ? __LINE__ : $line ) );
            
         }  

         /**
          * 
          * Metodo: getLogger
          * Descripcion: 
          * Fecha de Creacion: 19/04/2012 15:00:52
          * Autor: Juan José Muñiz Juárez
          * params: @param unknown_type $class
          * return: return_type
          */
      private static function getLogger( $class )
        {
           if ( self::$_log )
             {
                self::$_log -> setClass( $class == null ? __CLASS__ : $class );
             }
           else
             {
                self::$_log = new Logger( $class == null ? __CLASS__ : $class  );
             }  
        }	
   }